#include "sync.h"
#include "interrupt.h"
#include "global.h"
#include "../kernel/debug.h"

void sema_init(struct semaphore* psema, uint8_t value)
{
    psema->value = value;
    list_init(&psema->waiters);
}

void sema_down(struct semaphore* psema)
{
    enum intr_status old_status = intr_disable(); 
    while(psema->value <= 0){//无法获取，需要等待
        struct task_struct * curr = current_thread();
        list_append(&psema->waiters,&curr->generalListElement);
        thread_block(TASK_BLOCKED);
    }
        
    psema->value--;
    set_intr_status(old_status);
}
void sema_up(struct semaphore* psema)
{
    enum intr_status old_status = intr_disable(); 
    psema->value++;
    if( !list_empty(&psema->waiters)){
        struct list_elem* nextElem = list_pop(&psema->waiters);
        struct task_struct* next = member_to_entry(struct task_struct,generalListElement,nextElem);
        thread_unblock(next);
    }
   set_intr_status(old_status);
}

void lock_init(struct lock* plock)
{
    plock->holder = NULL;
    sema_init(&plock->semaphore,1);
    plock->holderCount = 0;
}

void lock_acquire(struct lock* plock)
{
    struct task_struct* curr =  current_thread();
    if(curr ==  plock->holder){
        plock->holderCount++;
    }else{
        sema_down(&plock->semaphore);
        plock->holder = curr;
        plock->holderCount = 1;
    }
}

void lock_release(struct lock* plock)
{
    ASSERT(plock->holder == current_thread());
    
    plock->holderCount --;
    if(plock->holderCount <= 0){
        plock->holder = NULL;
        sema_up(&plock->semaphore);
    }
}